#include "DepthCubeMapRenderPass.h"
#include <SEDRPPlugin/GBuffer.h>
#include <SERender/Descriptors/FrameDescriptor.h>
#include <SEngine/Render/RenderFeature/UtilRenderFeature.h>
#include <SERender/Renderer/Renderer.h>
#include <SEngine/Render/Descriptors/SceneDescriptor.h>
#include <SEngine/Render/RenderFeature/ModelRenderFeature.h> 
#include <SECore/Ecs/Scene.h>
#include <SEngine/Ecs/Components/ModelRenderComp.h>
#include <SEngine/Ecs/Components/TransformComp.h>
#include <SEngine/Ecs/Components/LightComp.h>
#include <SEUi/SEUi.h>
#include <SERender/Resourses/Loader/ShaderLoader.h>
#include <SEngine/Render/RenderFeature/UBORenderFeature.h>
#include <SEUi/Util/Util.h>
#include <SEngine/Render/RenderFeature/SkyBoxRenderFeature.h>


namespace SEngine
{
    DepthCubeMapRenderPass::DepthCubeMapRenderPass(Renderer &renderer)
        : RenderPass(renderer)
    {
        m_depthCubeMapMaterial = Manager::GetInstance().Get<Material>("DepthCubeMap").value();
        m_fbo = std::make_unique<FrameBuffer>();
    }

    void DepthCubeMapRenderPass::DrawFrame()
    {
        static float zFar = 1000.0f;
        auto scene = m_renderer.AnyDescriptor::GetDescriptor<SceneDescriptor>()->get().scene;
        auto & gbuffer = m_renderer.AnyDescriptor::GetDescriptor<GBuffer>()->get();
        auto & frame = m_renderer.AnyDescriptor::GetDescriptor<FrameDescriptor>()->get();
        auto & modelFeature = m_renderer.Descriptor<RenderFeature>::GetDescriptor<ModelRenderFeature>()->get();
        auto & skyBoxFeature = m_renderer.Descriptor<RenderFeature>::GetDescriptor<SkyBoxRenderFeature>()->get();
        glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, zFar); // 距离1000之外的不管
        gbuffer["DepthCubeMapRT"]->Resize(1024, 1024); // 深度图分辨率1024应该足够
        scene->Components<PointLightComp, TransformComp>([&](Actor & actor, PointLightComp& light, TransformComp & trans) {
            glm::vec3 worldPos = glm::vec3(trans.GetTranslateMatrix() * glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
            glm::mat4 captureViews[] = {
                glm::lookAt(worldPos, worldPos + glm::vec3( 1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f)),
                glm::lookAt(worldPos, worldPos + glm::vec3(-1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f)),
                glm::lookAt(worldPos, worldPos + glm::vec3( 0.0f,  1.0f,  0.0f), glm::vec3(0.0f,  0.0f,  1.0f)),
                glm::lookAt(worldPos, worldPos + glm::vec3( 0.0f, -1.0f,  0.0f), glm::vec3(0.0f,  0.0f, -1.0f)),
                glm::lookAt(worldPos, worldPos + glm::vec3( 0.0f,  0.0f,  1.0f), glm::vec3(0.0f, -1.0f,  0.0f)),
                glm::lookAt(worldPos, worldPos + glm::vec3( 0.0f,  0.0f, -1.0f), glm::vec3(0.0f, -1.0f,  0.0f)),
            };
            m_renderer.UseFrameBuffer(*m_fbo, [&]() {
                // 生成深度贴图
                m_depthCubeMapMaterial.Value().Set("lightPos", worldPos);
                m_depthCubeMapMaterial.Value().Set("project", captureProjection);
                m_fbo->ClearAttachments();
                m_renderer.GetDrive()->Viewport(0, 0, 1024, 1024);
                m_fbo->Resize(1024, 1024);
                for (int i = 0; i < 6; ++i) {
                    m_depthCubeMapMaterial.Value().Set("view", captureViews[i]);
                    m_fbo->SwapAttachments(COLOR_ATTACHMENT0, *gbuffer["DepthCubeMapRT"], TEXTURE_CUBE_MAP_POSITIVE_X + i);
                    m_fbo->Use();
                    m_renderer.GetDrive()->Clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
                    scene->Components<ModelRenderComp>([&modelFeature, this](Actor & actor, ModelRenderComp & comp) {
                        modelFeature.DrawModel(comp.m_model, m_depthCubeMapMaterial);
                    });
                }
                m_renderer.GetDrive()->Viewport(frame.x, frame.y, frame.w, frame.h);
            });
            // 记录到shadowMap
        });
        ShowRT("ShadowMapRT", gbuffer["ShadowMapRT"]->GetId());


        SignalUpdateUI.AddSlot([this]() {
            ImGui::PushID("DepthCubeMapRenderPass");
            if (ImGui::CollapsingHeader("DepthCubeMapRenderPass")) {
                if (ImGui::Button("Reload")) {
                    m_depthCubeMapMaterial.Value().GetShader().Reload([](auto & path, auto & name) {
                        ShaderLoader loader;
                        return loader.Load(path).CreateShader(EngineUniformBlockBinder());
                    });
                }
                ImGui::DragFloat("zFar", &zFar, 0.1f, 0.1f, 10000.0f);
            }
            ImGui::PopID();
            return SlotState::Once;
        });

    }

} // namespace SEngine

